﻿// Inner Fire 游戏引擎库
// UI - UI管理器
//
// Copyright (c) 2024 by 尔西大帝. All rights reserved.
//
// 用于UI的管理器
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-12-25

#include "ui_manager.h"
#include <game/manager/game_manager.h>
#include <knumber.h>
#include <ui/component/label.h>
#include <xml_reader.h>

namespace ifire::ui {

UIManager::UIManager(
    ifire::game::GameManager* gm, const std::string_view& filename)
    : gm_(gm) {
  XmlReader xml(filename.data());
  auto& node = xml.Root();
  // 载入Sprite
  std::string_view sprite_path = node("SpritePath");
  sprites_ = Xml_ReadItemsPtrs<SpritePack>(sprite_path, "SpritePack");

  // 载入文字
  auto default_font = std::make_unique<BMFont>(node("DefaultFont"));
  default_font_ = default_font.get();
  // 这里有一个TIPS，我去问AI，这样的数组是不是不需要使用std::move语义。他说可以
  // 但是如果你没有移动构造函数（已经被我delete)，这是不行的，必须手动使用。
  bmfonts_.push_back(std::move(default_font));

  // 文字默认属性
  default_font_size_ = node("DefaultFontSize");
  default_text_padding_ = node("DefaultTextPadding");
}

SpritePack* UIManager::GetSpritePack(ikit::sstr name) {
  for (size_t i = 0; i < sprites_.size(); i++) {
    if (sprites_[i]->name == name) {
      return sprites_[i].get();
    }
  }
  return nullptr;
}

SpriteElement* UIManager::GetSpriteElement(ikit::sstr pack_element) {
  size_t colon_pos = pack_element.index_of(':');
  if (colon_pos == -1) {
    return nullptr; // 没有找到冒号，返回nullptr
  }

  ikit::sstr pack_name = pack_element.substr(0, colon_pos);
  ikit::sstr element_name = pack_element.substr(colon_pos + 1);

  // 得到Pack
  auto pack = GetSpritePack(pack_name);
  if (pack == nullptr) {
    return nullptr;
  }
  auto element = pack->FindElement(element_name);
  // 如果项目为空，则给出提示，并且置换默认项目
  if (element == nullptr) {
    KERROR("*UIManager* Unable find image: %s:%s", pack_name.log_str(),
        element_name.log_str());
    element = gm_->GetEmptyUIElement();
  }

  return element;
}

XMFLOAT2 UIManager::GetAdjustPosition(const dx::UIWidget& widget) const {
  XMFLOAT2 pos{};
  auto client_size = GetClientSize();

  if (widget.align.horizontal == dx::HorizontalAlignment::LEFT) {
    pos.x = widget.position.x;
  } else if (widget.align.horizontal == dx::HorizontalAlignment::CENTER) {
    pos.x = widget.position.x + client_size.x * 0.5f;
  } else if (widget.align.horizontal == dx::HorizontalAlignment::RIGHT) {
    pos.x = client_size.x - widget.position.x;
  }

  if (widget.align.vertical == dx::VerticalAlignment::TOP) {
    pos.y = widget.position.y;
  } else if (widget.align.vertical == dx::VerticalAlignment::MID) {
    pos.y = widget.position.y + client_size.y * 0.5f;
  } else if (widget.align.vertical == dx::VerticalAlignment::BOTTOM) {
    pos.y = client_size.y - widget.position.y;
  }

  return pos;
}

Label* UIManager::FindLabel(ikit::sstr name) {
  for (auto& e : labels_) {
    if (e->Name() == name) {
      return e.get();
    }
  }
  return nullptr;
}

Button* UIManager::FindButton(ikit::sstr name) {
  for (auto& e : buttons_) {
    if (e->Name() == name) {
      return e.get();
    }
  }
  return nullptr;
}

void UIManager::OnMouseMove(XMFLOAT2 delta, XMFLOAT2 pos) {
  // 遍历Button（目前仅简单的即可，以后需要功能再扩展）
  for (auto& e : Buttons()) {
    auto widget = e->Layout()->CalcWidget();
    e->SetHover(widget.IsHit(pos));
  }
}

bool UIManager::OnMouseDown(XMFLOAT2 pos) {
  bool is_hit = false;
  for (auto& e : Buttons()) {
    auto widget = e->Layout()->CalcWidget();
    if (widget.IsHit(pos)) {
      e->SetPushed(true);
      is_hit = true;
    }
  }
  return is_hit;
}

bool UIManager::OnMouseUp(XMFLOAT2 pos) {
  bool is_hit = false;
  for (auto& e : Buttons()) {
    auto widget = e->Layout()->CalcWidget();
    // 点击的逻辑如下：
    // 1、需要对象先被按下，也就是IsPushed为True。否则不需要进行判断。
    // 2、如果抬起鼠标按钮的时候，鼠标已经离开按钮范围，则判断为取消（WINDOWS就是这么做的）
    // 3、不管点击是否成功，抬起鼠标的时候，IsPushed都会设置为False。
    if (e->IsPushed()) {
      if (widget.IsHit(pos)) {
        e->PerformClick();
        is_hit = true;
      }
      e->SetPushed(false);
    }
  }
  return is_hit;
}

XMFLOAT2 UIManager::GetClientSize() const {
  return gm_->GetGraphics()->GetClientSize();
}

dx::DxTextDesc UIManager::CreateTextDesc(const LabelInfo& info) const {
  dx::DxTextDesc desc{};
  desc.pText = info.text.c_str();
  desc.Length = info.text.size();
  desc.Capacity = ikit::pick_default(info.capacity, desc.Length + 1);
  desc.FontSize = ikit::pick_default(info.font_size, DefaultFontSize());
  desc.TextPadding =
      ikit::pick_default(info.text_padding, DefaultTextPadding());
  desc.TextAlign = info.text_align;
  desc.Widget = info.widget;
  // 因为暂时没有管理的系统，所以Font的设置无效，之后再改进
  desc.Font = DefaultFont();
  // 这个ClientSize是为了自动计算宽高
  desc.ClientSize = GetClientSize();
  return desc;
}

dx::DxImageDesc UIManager::CreateImageDesc(
    SpriteElement* sprite, const dx::UIWidget& widget) const {
  dx::DxImageDesc desc{};
  desc.pElement = sprite;
  desc.Widget = widget;
  return desc;
}

dx::DxLayoutDesc UIManager::CreateLayoutDesc(const dx::UIWidget& widget) const {
  dx::DxLayoutDesc desc{};
  desc.Widget = widget;
  return desc;
}

Label* UIManager::CreateLabel(
    ikit::sstr name_id, ikit::sstr prefab_name, XMFLOAT2 position) {
  // 得到Prefab
  auto prefab = gm_->GetConfig()->GetUIPrefab(prefab_name);
  if (prefab == nullptr) {
    KERROR("*UIManager* Unable find label prefab: %s", prefab_name.c_str());
    return nullptr;
  }

  // 创建一个Label，并且加入到队列
  auto ptr = std::make_unique<Label>(name_id, prefab->GetLabelInfo());
  auto label = ptr.get();
  labels_.push_back(std::move(ptr));

  // 从DirectX中创建
  auto desc = CreateTextDesc(*label->Info());
  dx::UIRenderItem* parent = nullptr; // 父级，现在使用不上，这个看以后怎么办
  auto dx_text = gm_->GetGraphics()->CreateText(desc, parent);

  // 设置Direct的文字到Label
  label->SetLabelText(dx_text);

  // 设置位置
  label->SetPosition(position);

  // 返回对象
  return label;
}

Button* UIManager::CreateButton(ikit::sstr name_id, ikit::sstr prefab_name,
    ikit::sstr button_icon, const char* button_text, XMFLOAT2 position) {
  // 得到Prefab
  auto prefab = gm_->GetConfig()->GetUIPrefab(prefab_name);
  if (prefab == nullptr) {
    KERROR("*UIManager* Unable find button prefab: %s", prefab_name.c_str());
    return nullptr;
  }

  // 创建一个Button，并且加入到队列
  auto ptr = std::make_unique<Button>(name_id, prefab->GetButtonInfo());
  auto button = ptr.get();
  buttons_.push_back(std::move(ptr));

  // 从DirectX中创建
  auto info = prefab->GetButtonInfo();

  // 创建Button的容器
  auto widget = info->widget; // 复制一个widget，需要改变Position
  widget.position = position;
  auto button_layout = CreateLayout(widget);
  button->SetLayout(button_layout);

  CreateImage(button->ButtonImage(), button_layout);

  // 创建Icon
  auto icon = button->IconImage();
  if (icon->Info()->is_validate) {
    auto sprite = icon->Info();
    auto element = GetSpriteElement(button_icon); // 这里替换掉内置的项目
    auto image_desc = CreateImageDesc(element, sprite->widget);
    auto dx_image = gm_->GetGraphics()->CreateImage(image_desc, button_layout);
    icon->SetImage(dx_image);
  }

  // 创建Button的Label
  auto text_info = button->Text();
  if (text_info && text_info->Info()->is_validate) {
    auto text_desc = CreateTextDesc(*text_info->Info());
    text_desc.pText = button_text; // 这里覆盖掉原来的项目
    text_desc.Length = strlen(button_text);
    auto dx_text = gm_->GetGraphics()->CreateText(text_desc, button_layout);
    button->Text()->SetLabelText(dx_text);
  }

  button->ButtonImage()->SetVisible(false);
  if (button->Text()) {
    button->Text()->SetVisible(false);
  }
  // button->AddClickListener(on_click);
  button->SetDefaultHoverAction();
  button->SetDefaultPushedAction();

  return button;
}

Image* UIManager::CreateImage(ikit::sstr name_id, ikit::sstr prefab_name,
    ikit::sstr image_icon, XMFLOAT2 position) {
  // 得到Prefab
  auto prefab = gm_->GetConfig()->GetUIPrefab(prefab_name);
  if (prefab == nullptr) {
    KERROR("*UIManager* Unable find image prefab: %s", prefab_name.log_str());
    return nullptr;
  }

  // 创建一个Image，并且加入到队列
  auto ptr = std::make_unique<Image>(name_id, prefab->GetImageInfo());
  auto image = ptr.get();
  images_.push_back(std::move(ptr));

  // 从DirectX中创建
  auto sprite = prefab->GetImageInfo();
  auto element = GetSpriteElement(image_icon); // 这里替换掉内置的项目
  auto image_desc = CreateImageDesc(element, sprite->widget);
  auto dx_image = gm_->GetGraphics()->CreateImage(image_desc, nullptr);
  image->SetImage(dx_image);

  // 设置位置
  image->SetPosition(position);

  return image;
}

void UIManager::CreateImage(ui::Image* img, dx::UIRenderItem* parent) {
  // 跳过非法的项目
  if (img == nullptr || img->Info()->is_validate == false) {
    return;
  }

  auto sprite = img->Info();
  auto element = GetSpriteElement(sprite->sprite);
  auto desc = CreateImageDesc(element, sprite->widget);
  auto dx_image = gm_->GetGraphics()->CreateImage(desc, parent);
  img->SetImage(dx_image);
}

dx::DxLayout* UIManager::CreateLayout(
    const dx::UIWidget& widget, dx::UIRenderItem* parent) {
  auto desc = CreateLayoutDesc(widget);
  return gm_->GetGraphics()->CreateLayout(desc, parent);
}

} // namespace ifire::ui
